package com.zmn.oms.third.daowei;

import com.alibaba.fastjson.JSON;
import com.zmn.oms.common.enums.ChannelFacade;
import com.zmn.oms.common.utils.HttpUtil;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.third.core.tracker.FacadeTracker;
import com.zmn.oms.third.daowei.dto.BaseRsp;
import com.zmn.oms.third.daowei.dto.PayQrCodeRsp;
import com.zmn.oms.third.daowei.dto.RushOrderRsp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

/**
 * 类描述：
 *
 * @author lhl
 * @date 2020/02/21 16:00
 */
@Slf4j
public class DaoweiApiInvoker {

    /**
     * 同步接单（派单） ongoing
     * @param orderWork
     * @return
     */
    public static RushOrderRsp rushToAcceptOrder(String appkey, OrderWork orderWork) {
        RushOrderRsp failRsp = new RushOrderRsp();
        failRsp.setStatus("error");

        DaoweiConsts.ChannelInfo channelInfo = DaoweiConsts.channelInfo(appkey, true);
        if (channelInfo == null) {
            failRsp.setMsg("无匹配渠道");
            return failRsp;
        }

        Map<String, String> params = new HashMap<>();
        params.put("status", DaoweiConsts.SYNC_STATUS_ONGOING);
        params.put("orderId", String.valueOf(orderWork.getOrderId()));
        params.put("daowayOrderId", orderWork.getOuterId());
        params.put("appkey", channelInfo.getAppkey());
        params.put("oncestr", String.valueOf(System.currentTimeMillis() / 1000));
        params.put("sign", _signMd5(params, channelInfo.getSecret()));

        String response = null;

        FacadeTracker.FacadeTrackerCore tracker = FacadeTracker.getTracker();
        try {
            String paramsJson = JSON.toJSONString(params);
            tracker.reqSummary(paramsJson);
            log.info("【{}】数据同步请求：[{}], [{}]", channelInfo.getName(), DaoweiConsts.DAOWEI_API_URL, paramsJson);
            response = HttpUtil.httpsPost(DaoweiConsts.DAOWEI_API_URL, params);
            if (response != null) {
                response = response.replaceAll("[\\r|\\n]", "");
            }
            log.info("【{}】数据同步结果：[{}]", channelInfo.getName(), response);
            tracker.success(true).respSummary(response);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            tracker.error(e, null);
            failRsp.setMsg("网络异常");
            return failRsp;
        }

        try {
            RushOrderRsp rushOrderRsp = JSON.parseObject(response, RushOrderRsp.class);
            if (rushOrderRsp == null) {
                failRsp.setMsg(String.format("解析结果失败：response=[%s]", response));
                return failRsp;
            }
            return rushOrderRsp;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            tracker.error(e, null);
            failRsp.setMsg(String.format("解析结果失败：response=[%s]", response));
            return failRsp;
        }
    }

    /**
     * 获取支付二维码
     * @param appkey
     * @param orderWork
     * @param bill
     * @return
     */
    public static PayQrCodeRsp requestPayQrCode(String appkey, OrderWork orderWork, Double bill) {
        FacadeTracker.FacadeTrackerCore tracker = FacadeTracker.getTracker()
                .dataOut(ChannelFacade.DAOWEI)
                .remark("获取支付二维码")
                .orderId(orderWork.getOrderId());

        PayQrCodeRsp payQrCodeRsp = requestPayQrCode_0(appkey, orderWork, bill);

        tracker.success("ok".equals(payQrCodeRsp.getStatus()))
                .remark(payQrCodeRsp.getMsg())
                .commit();

        return payQrCodeRsp;
    }

    public static void main(String[] args) {
        // 测试地址
        //DaoweiConsts.DAOWEI_API_URL = "http://test.daoway.cn:8080/daoway/rest/order_notify";
        // 线上地址
        DaoweiConsts.DAOWEI_API_URL = "http://api.daoway.cn/daoway/rest/order_notify";

        long orderId = 571018869011914752L;
        String outerId = "210223165955720";
        String appkey = "q5dytuhz9ug7noivnxez6w1o8cmmae7x";


        OrderWork orderWork = new OrderWork();
        orderWork.setOrderId(orderId);
        orderWork.setOuterId(outerId);

        PayQrCodeRsp payQrCodeRsp = requestPayQrCode_0(appkey, orderWork, new Double(21));

        System.out.println(JSON.toJSONString(payQrCodeRsp));
    }

    /**
     * 获取支付二维码
     * @param appkey
     * @param orderWork
     * @param bill
     * @return
     */
    private static PayQrCodeRsp requestPayQrCode_0(String appkey, OrderWork orderWork, Double bill) {
        PayQrCodeRsp payQrCodeRsp = new PayQrCodeRsp();
        payQrCodeRsp.setStatus("error");

        DaoweiConsts.ChannelInfo channelInfo = DaoweiConsts.channelInfo(appkey, true);
        if (channelInfo == null) {
            payQrCodeRsp.setMsg("无匹配渠道");
            return payQrCodeRsp;
        }

        Map<String, String> params = new HashMap<>();
        params.put("status", DaoweiConsts.SYNC_STATUS_SET_DIFF);

        params.put("orderId", String.valueOf(orderWork.getOrderId()));
        params.put("daowayOrderId", orderWork.getOuterId());
        params.put("bill", String.format("%.2f", bill));
        /* fillPriceDiffType ：支付二维码类型   2020.12.23 by lhl
            alipay：返回支付宝收款二维码；
            wx：返回微信收款二维码
        */
        params.put("fillPriceDiffType", "set_diff");

        params.put("appkey", channelInfo.getAppkey());
        params.put("oncestr", String.valueOf(System.currentTimeMillis() / 1000));
        params.put("sign", _signMd5(params, channelInfo.getSecret()));

        String response = null;

        FacadeTracker.FacadeTrackerCore tracker = FacadeTracker.getTracker();
        try {
            String paramsJson = JSON.toJSONString(params);
            tracker.reqSummary(paramsJson);
            log.info("【{}】数据同步请求：[{}], [{}]", channelInfo.getName(), DaoweiConsts.DAOWEI_API_URL, paramsJson);
            response = HttpUtil.httpsPost(DaoweiConsts.DAOWEI_API_URL, params);
            if (response != null) {
                response = response.replaceAll("[\\r|\\n]", "");
            }
            log.info("【{}】数据同步结果：[{}]", channelInfo.getName(), response);
            tracker.success(true).respSummary(response);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            tracker.error(e, null);
            payQrCodeRsp.setMsg("网络异常");
            return payQrCodeRsp;
        }

        try {
            PayQrCodeRsp rsp = JSON.parseObject(response, PayQrCodeRsp.class);
            if (rsp == null) {
                payQrCodeRsp.setMsg(String.format("解析结果失败：response=[%s]", response));
                return payQrCodeRsp;
            }
            return rsp;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            tracker.error(e, null);
            payQrCodeRsp.setMsg(String.format("解析结果失败：response=[%s]", response));
            return payQrCodeRsp;
        }
    }

    /**
     * 同步接单（派单） ongoing
     * @param orderWork
     * @return
     */
    public static BaseRsp pushOrderReceipt(String appkey, OrderWork orderWork) {
        Map<String, String> params = new HashMap<>();
        params.put("status", DaoweiConsts.SYNC_STATUS_ONGOING);

        params.put("orderId", String.valueOf(orderWork.getOrderId()));
        params.put("daowayOrderId", orderWork.getOuterId());

        return notifyOrderStatus(orderWork.getChannelId(), appkey, params);
    }

    /**
     * 同步预约时间，同步预约时间不需要更改状态，所以不用传状态参数
     * @param orderWork
     * @return
     */
    public static BaseRsp pushDutyTime(String appkey, OrderWork orderWork) {
        Map<String, String> params = new HashMap<>();

        params.put("orderId", String.valueOf(orderWork.getOrderId()));
        params.put("daowayOrderId", orderWork.getOuterId());

        // 预约时间，long类型，单位毫秒
        params.put("appointTime", String.valueOf(orderWork.getDutyTime().getTime()));

        return notifyOrderStatus(orderWork.getChannelId(), appkey, params);
    }

    /**
     * 同步取消   canceled
     *   注意：状态为已接单（ongoing）的订单，用户未申请退款的情况下，商家再单方面通过该接口取消订单（将状态更新为canceled），
     *   或者全额退款（part_return的定额等于用户支付的金额）视为商家爽约，将自动触发“商家爽约赔付”流程向用户赔付；
     *   如果是用户主动要求取消订单的，商家客服需引导用户在到位平台先发起退款申请，再取消订单或退款即无需赔付。
     * @param orderWork
     * @param remark
     * @return
     */
    public static BaseRsp pushOrderCancel(String appkey, OrderWork orderWork, String remark) {
        Map<String, String> params = new HashMap<>();
        params.put("status", DaoweiConsts.SYNC_STATUS_CANCELED);

        params.put("orderId", String.valueOf(orderWork.getOrderId()));
        params.put("daowayOrderId", orderWork.getOuterId());

        // 取消订单时，note不能为空
        if (StringUtils.isBlank(remark)) {
            remark = "订单取消了";
        }
        params.put("note", remark);

        return notifyOrderStatus(orderWork.getChannelId(), appkey, params);
    }

    /**
     * 同步完成   completed
     * @param orderWork
     * @return
     */
    public static BaseRsp pushOrderComplete(String appkey, OrderWork orderWork) {
        Map<String, String> params = new HashMap<>();
        params.put("status", DaoweiConsts.SYNC_STATUS_COMPLETED);

        params.put("orderId", String.valueOf(orderWork.getOrderId()));
        params.put("daowayOrderId", orderWork.getOuterId());

        return notifyOrderStatus(orderWork.getChannelId(), appkey, params);
    }

    /**
     * 同步拒绝退款
     * @param orderWork
     * @return
     */
    public static BaseRsp pushRejectRefund(String appkey, OrderWork orderWork, String remark) {
        Map<String, String> params = new HashMap<>();
        params.put("status", DaoweiConsts.SYNC_STATUS_REJECT_REFUND);

        params.put("orderId", String.valueOf(orderWork.getOrderId()));
        params.put("daowayOrderId", orderWork.getOuterId());
        // 拒绝退款时，note不能为空
        if (StringUtils.isBlank(remark)) {
            remark = "退款失败";
        }
        params.put("note", remark);

        return notifyOrderStatus(orderWork.getChannelId(), appkey, params);
    }

    /**
     * 同步同意退款
     * @param orderWork
     * @return
     */
    public static BaseRsp pushApproveRefund(String appkey, OrderWork orderWork) {
        Map<String, String> params = new HashMap<>();
        params.put("status", DaoweiConsts.SYNC_STATUS_APPROVE_REFUND);

        params.put("orderId", String.valueOf(orderWork.getOrderId()));
        params.put("daowayOrderId", orderWork.getOuterId());

        return notifyOrderStatus(orderWork.getChannelId(), appkey, params);
    }

    /**
     * 同步需要补差价金额（用户需在到位平台补差价） set_diff
     * @param orderWork
     * @return
     */
    public static BaseRsp pushPriceDifference(String appkey, OrderWork orderWork, Double bill) {
        Map<String, String> params = new HashMap<>();
        params.put("status", DaoweiConsts.SYNC_STATUS_SET_DIFF);

        params.put("orderId", String.valueOf(orderWork.getOrderId()));
        params.put("daowayOrderId", orderWork.getOuterId());

        params.put("bill", String.format("%.2f", bill));

        return notifyOrderStatus(orderWork.getChannelId(), appkey, params);
    }

    /**
     * 同步啄木鸟收款额（用户在商家平台补差价）    order_diff
     * @param orderWork
     * @param bill
     * @return
     */
    public static BaseRsp pushMasterAmount(String appkey, OrderWork orderWork, Double bill) {
        Map<String, String> params = new HashMap<>();
        params.put("status", DaoweiConsts.SYNC_STATUS_ORDER_DIFF);

        params.put("orderId", String.valueOf(orderWork.getOrderId()));
        params.put("daowayOrderId", orderWork.getOuterId());

        params.put("bill", String.format("%.2f", bill));

        return notifyOrderStatus(orderWork.getChannelId(), appkey, params);
    }

    /**
     * 给到位同步订单状态
     * @param channelId
     * @param params
     */
    private static BaseRsp notifyOrderStatus(int channelId, String orderAppkey, Map<String, String> params) {
        BaseRsp rsp = null;
        FacadeTracker.FacadeTrackerCore tracker = FacadeTracker.getTracker();

        do {
            boolean isQuick = DaoweiConsts.CHANNEL_ID_ZX == channelId;
            DaoweiConsts.ChannelInfo channelInfo = DaoweiConsts.channelInfo(orderAppkey, isQuick);
            if (channelInfo == null) {
                rsp = _newFailBaseRsp("无匹配渠道");
                break;
            }

            params.put("appkey", channelInfo.getAppkey());
            params.put("oncestr", String.valueOf(System.currentTimeMillis() / 1000));
            params.put("sign", _signMd5(params, channelInfo.getSecret()));

            String response = null;
            try {
                String paramsJson = JSON.toJSONString(params);
                tracker.reqSummary(paramsJson);
                log.info("【{}】数据同步请求：[{}], [{}]", channelInfo.getName(), DaoweiConsts.DAOWEI_API_URL, paramsJson);
                response = HttpUtil.httpsPost(DaoweiConsts.DAOWEI_API_URL, params);
                if (response != null) {
                    response = response.replaceAll("[\\r|\\n]", "");
                }
                log.info("【{}】数据同步结果：[{}]", channelInfo.getName(), response);
                tracker.respSummary(response);
            } catch (Exception e) {
                tracker.error(e, e.getMessage());
                log.error(e.getMessage(), e);
                rsp = _newFailBaseRsp("网络异常");
                break;
            }

            try {
                rsp = JSON.parseObject(response, BaseRsp.class);
            } catch (Exception e) {
                tracker.error(e, null);
                log.error(e.getMessage(), e);
                rsp = _newFailBaseRsp(String.format("解析结果失败：response=[%s]", response));
                break;
            }

            // 转换结果
            if (rsp == null) {
                return _newFailBaseRsp(String.format("解析结果失败：response=[%s]", response));
            }
        } while (false);

        tracker.success("ok".equals(rsp.getStatus()), rsp.getMsg());
        return rsp;
    }

    /**
     * 计算签名
     * @param paramValues
     * @param secret
     * @return
     */
    private static String _signMd5(Map<String, String> paramValues, String secret) {
        StringBuilder sb = new StringBuilder();
        List<String> paramNames = new ArrayList<String>(paramValues.size());
        paramNames.addAll(paramValues.keySet());

        Collections.sort(paramNames);

        for (String paramName : paramNames) {
            // 空值不参与签名
            try {
                sb.append(paramName).append("=").append(URLEncoder.encode(paramValues.get(paramName), "utf-8")).append("&");
            } catch (UnsupportedEncodingException e) {
            }
        }
        sb.append("secret=").append(secret);

        String str = sb.toString();
        log.info("[Daowei-sign-MD5] parms=[{}]", str);

        return DigestUtils.md5Hex(str).toUpperCase();
    }

    /**
     * 生成一个错误结果对象
     * @param errorMsg
     * @return
     */
    private static BaseRsp _newFailBaseRsp(String errorMsg) {
        BaseRsp rsp = new BaseRsp();
        rsp.setStatus("error");
        rsp.setMsg(errorMsg);
        return rsp;
    }
}
